/*
 * JavaScript components for bogglesolver
 */

var xhrs = false;

function is_alpha(charin) {
  var LETTERS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
  if (LETTERS.indexOf(charin) >= 0) return true;
  return false;
}

function logdebug(text) {
  var debug = document.getElementById('debug');
  debug.innerHTML = debug.innerHTML + "<br/>" + text;
}

function length_diff(a,b) {
  return b[0].length - a[0].length;
}

function handle_solve_partial_reply() {
  update_status();
  var words = new Array();
  // Load in all the words...
  for (xhr in xhrs) {
    if (xhrs[xhr].readyState == 4) {
      // Parse JSON word output
      var new_words = eval('(' + xhrs[xhr].responseText + ')');
      for (word in new_words) {
        words.push(new_words[word]);
      }
    }
  }
  // Now dedup all the words...
  words.sort(function (a,b){return a[0]>b[0]?1:-1;});
  var last_word = "";
  var nodup_words = new Array();
  for (word in words) {
    if (words[word][0] != last_word[0]) {
      nodup_words.push(words[word]);
    } else {
      // We already found this word, push the extra locations
      nodup_words[nodup_words.length-1].push(words[word][1])
    }
    last_word = words[word];
  }
  // Now present them in longest word first order...
  nodup_words.sort(length_diff);
  var result_div = document.getElementById('result');
  var output_text = ""
  for (idx in nodup_words) {
    var insert_text = "";
    word = nodup_words[idx][0];
    squares = nodup_words[idx][1];
    insert_text = (
        "<div><span onmouseover='lightsquares(this, [" + squares +"])' " +
             "onmouseout='unlightsquares(this, [" + squares +"])' " +
        ">" + word + "</span>");
    for (i = 2; i < nodup_words[idx].length; i++) {
      insert_text = (insert_text +
        "<span onmouseover='lightsquares(this, [" + nodup_words[idx][i] + "])' " +
              "onmouseout='unlightsquares(this, [" + nodup_words[idx][i] + "])' " +
        ">&lt;</span>");
    }
    insert_text = insert_text + "</div>";
    output_text = output_text + insert_text;
  }
  result_div.innerHTML = output_text;
}

function solve_puzzle() {
  var puzzle = document.getElementById('puzzle').value;
  var status = document.getElementById('status');

  // Validate puzzle input has sane dimensions
  var root = parseInt(Math.sqrt(puzzle.length));
  
  if (root * root != puzzle.length) {
    status.style.display = "block";
    status.innerHTML = "USER ERROR: Non-square input.";
    return;
  }
  
  var progress = document.getElementById('progress');
  var puzzle_element = document.getElementById('puzzle');
  var solve_button = document.getElementById('solve');
  var random_button = document.getElementById('random');
  status.style.display = "none";
  progress.style.display = "block";
  puzzle_element.disabled = true;
  solve_button.disabled = true;
  random_button.disabled = true;
  /* Make sure we're rendering the right thing */
  update_puzzlesquares(puzzle_element);

  // An array for our parallel solvers
  xhrs = new Array(puzzle.length);

  /* Hack for early, stupid, vulnerable to exploits versions of MSIE */
  if (!XMLHttpRequest) {
    window.XMLHttpRequest = function() {
      return new ActiveXObject('Microsoft.XMLHTTP');
    }
  }
  
  for (x=0; x<root; x++) {
    for (y=0; y<root; y++) {
      var index = (y * root) + x;
      
      xhrs[index] = new XMLHttpRequest();
      // TODO(wac): Real values for x and y here
      url = "/solve_partial?board=" + puzzle + "&x="+x+"&y="+y;
      xhrs[index].onreadystatechange = handle_solve_partial_reply;
      xhrs[index].open("GET", url, true);
      xhrs[index].send("");
    }
  }
  update_status();
}

function get_div_children(parent) {
  var returnval = new Array();
  
  for (idx in parent.childNodes) {
    var this_node = parent.childNodes[idx];
    if (this_node && this_node.nodeType == 1 && this_node.nodeName == 'DIV') {
      returnval.push(this_node);
    }
  }
  return returnval;
}

function status_keypress_handler() {
  /* And if they hit enter... solve the puzzle */
  if (window.event && window.event.keyCode == 13) solve_puzzle();
  return true;
}

function update_puzzlesquares(input_element) {
  var puzzle = input_element.value;
  var puzzlelen = puzzle.length;
  var status = document.getElementById('status');
  var puzzlesquares = document.getElementById('puzzlesquares');
  var puzzlerows = get_div_children(puzzlesquares);
  
  var rowlen = parseInt(Math.sqrt(puzzlelen));
  
  document.getElementById('result').innerHTML = "";
  
  if (rowlen * rowlen != puzzle.length) {
    status.style.display = "block";
    status.innerHTML = "You need to input a square number of letters.";
    if (puzzle.length > rowlen * rowlen) {
      rowlen = rowlen + 1;
    }
  } else {
    status.style.display = "none";
    status.innerHTML = "";
  }

  /* Make sure the correct number of blocks are in the puzzle */
  /* Add extra rows */
  while (puzzlerows.length < rowlen) {
    var new_row = document.createElement("div");
    new_row.className = "row";
    /* Put the correct number of elements in the row. */
    for (x=0; x<rowlen; x++) {
      var new_square = document.createElement("div");
      new_row.appendChild(new_square);
    }
    puzzlesquares.appendChild(new_row);
    puzzlerows = get_div_children(puzzlesquares);
  }

  /* Remove extra rows */
  while (puzzlerows.length > rowlen) {
    puzzlesquares.removeChild(puzzlerows[puzzlerows.length - 1]);
    puzzlerows = get_div_children(puzzlesquares);
  }
  
  /* Double-check squares */
  for (x=0; x<rowlen; x++) {
    /* We are guaranteed that puzzlerows[x] exists. */
    var current_row = puzzlerows[x];
    var current_squares = get_div_children(current_row);
    while (current_squares.length > rowlen) {
      current_row.removeChild(current_squares[current_squares.length - 1]);
      current_squares = get_div_children(current_row);
    }
    for (y=0; y<rowlen; y++) {
      if (y >= current_squares.length) {
        var new_square = document.createElement("div");
        current_row.appendChild(new_square);
        current_squares = get_div_children(current_row);
      }
      var current_square = current_squares[y];
      if (puzzlelen > x*rowlen + y) {
        var char_pos = x*rowlen + y;
        var char_square = puzzle.charAt(char_pos);
        current_square.innerHTML = char_square;
        current_square.id = "square"+ (x*rowlen + y);
        if (is_alpha(char_square)) {
          current_square.className = "";
          current_square.style.fontSizeAdjust = "none";
          if (char_square == "q" || char_square == "Q") {
            current_square.innerHTML = "Qu";
            current_square.style.fontSizeAdjust = "0.5";
          }
        } else {
          current_square.className = "badvalue";
          status.style.display = "block";
          status.innerHTML = "Something in there doesn't look like a letter.";
        }
      } else {
        current_square.innerHTML = "";
        current_square.className = "badvalue";
      }
    }
  }
}

function update_status() {
  var status_count = 0;
  var status_total = xhrs.length;
  for (xhr in xhrs) {
    if (xhrs[xhr].readyState == 4) {
      status_count = status_count + 1;
    }
  }
  var status_div = document.getElementById('status');
  var progress_div = document.getElementById('progress');
  var puzzle = document.getElementById('puzzle');
  var solve_button = document.getElementById('solve');
  var random_button = document.getElementById('random');
  if (status_count == status_total) {
    progress_div.style.display = "none";
    status_div.style.display = "none";
    puzzle.disabled = false;
    solve_button.disabled = false;
    random_button.disabled = false;
  } else {
    var bar_div = document.getElementById('bar');
    progress_div.style.display = "block";
    bar_div.style.width = (100*status_count/status_total) + "%"
  }
}

function lightsquares(word, square_list) {
  word.className = "highlight";
  word.parentNode.className = "highlight";
  for (i in square_list) {
    document.getElementById("square"+square_list[i]).className = "highlight"
  }
}

function unlightsquares(word, square_list) {
  word.className = "";
  word.parentNode.className = "";
  for (i in square_list) {
    document.getElementById("square"+square_list[i]).className = ""
  }
}

function randomsmallsquare() {
  var random_number = Math.random(); /* The emphasis in PRNG is on the pseudo */
  if (random_number < 0.08) return 9; /* You've failed the breathalizer */
  if (random_number < 0.75) return 16;
  if (random_number < 0.92) return 25;
  return 36; /* It's your pseudo-lucky day */
}

function randomize_input() {
  var LETTERS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
  var puzzle_element = document.getElementById('puzzle');
  var random_string = "";
  var new_length = randomsmallsquare();
  if (navigator.userAgent.indexOf("MSIE") != -1) {
    /* Let's have some fun */
    var random_number = Math.random();
    if (random_number < 0.2)
      random_string = "thoughtaboutarealbrowser?"
    else if (random_number < 0.4)
      random_string = "stopsufferingfirefox=free"
    else if (random_number < 0.6)
      random_string = "usingiekillsbabyseals,sad"
    else if (random_number < 0.8)
      random_string = "makethisjsworkinie?uh,no."
    else
      random_string = "plztobeupgradingyourbrowser kthxbai!"
  } else {
    for (var i=0; i < new_length; i++) {
      var random_char = LETTERS[Math.floor(Math.random() * 26)];
      random_string = random_string + random_char;
    }
  }
  puzzle_element.value = random_string;
  update_puzzlesquares(puzzle_element);
}
